//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <bulverde.h>
#include <tsc2302.h>
#include <i2s.h>
#include <misc.h>
#include "audio.h"

typedef union{
    struct{
        // [0]
        unsigned short     I2SFM: 2;
        unsigned short     I2SFS: 4;
        unsigned short     MCLK: 2;
        unsigned short     MICG: 2;
        unsigned short     INMR: 2;
        unsigned short     INML: 2;
        unsigned short     HPF: 2;

        // [1]
        unsigned short     ADVR: 7;
        unsigned short     ADMUR: 1;
        unsigned short     ADVL: 7;
        unsigned short     ADMUL: 1;

        // [2]
        unsigned short     DAVR: 7;
        unsigned short     DAMUR: 1;
        unsigned short     DAVL: 7;
        unsigned short     DAMUL: 1;

        // [3]
        unsigned short     BPVR: 7;
        unsigned short     BPMUR: 1;
        unsigned short     BPVL: 7;
        unsigned short     BPMUL: 1;

        // [4]
        unsigned short     SSTEP: 1;
        unsigned short     SSRTE: 1;
        unsigned short     MONS: 1;
        unsigned short     Res4_882: 13;

        // [5]
        unsigned short     DEEMP: 1;
        unsigned short     BASS: 1;
        unsigned short     OTSYN: 1;
        unsigned short     SMPD: 1;
        unsigned short     BCKC: 1;
        unsigned short     AOSCC: 1;
        unsigned short     MIBPD: 1;
        unsigned short     PDSTS: 1;
        unsigned short     ADPDR: 1;
        unsigned short     ADPDL: 1;
        unsigned short     DAPD: 1;
        unsigned short     MOPD: 1;
        unsigned short     HAPD: 1;
        unsigned short     ABPD: 1;
        unsigned short     AVPD: 1;
        unsigned short     APD: 1;

        // [6]
        unsigned short     Res6_00: 5;
        unsigned short     IO5: 1;
        unsigned short     Res6_000: 7;
        unsigned short     GPIO5: 1;
        unsigned short     Res6_0: 2;
    }RegByName;

    unsigned short RegByNumber[7];
}PAGE2_REG;

static PAGE2_REG Page2Reg;

//#define DEBUG_AUDIO
#ifdef DEBUG_AUDIO
void DumpTSC()
{
    int i;
    TSC_RegRead(2, 0, Page2Reg.RegByNumber, 7);
    msleep(1);
    TSC_RegRead(2, 0, Page2Reg.RegByNumber, 7);
    msleep(1);

    kprintf("Dump audio registers of TSC2302:\n");
    for ( i = 0; i < 7; i++) {
        kprintf("REGISTER%d = %x\n", i, Page2Reg.RegByNumber[i]);
    }
}

void DumpI2S()
{
    kprintf("Dump registers of I2S:\n");
    kprintf("SACR0 = %x\n", BV_SACR0);
    kprintf("SACR1 = %x\n", BV_SACR1);
    kprintf("SASR0 = %x\n", BV_SASR0);
    kprintf("SAIMR = %x\n", BV_SAIMR);
    kprintf("SAICR = %x\n", BV_SAICR);
    kprintf("SADIV = %x\n", BV_SADIV);
    kprintf("SADR  = %x\n", BV_SADR);
}
#endif

void TSC_SetFrequence(unsigned long  dwFrequence)
{
    Page2Reg.RegByName.I2SFS = (unsigned short)dwFrequence;
    TSC_RegWrite(2, 0, &Page2Reg.RegByNumber[0], 1);
    msleep(1);
}

void select_MIC_source(unsigned int source)
{
	GPDR1 |= MIC_CHOICE_GPIO56;
	GAFR1_U &=~(3<<16);
	switch(source)
	{
		case AUX_MIC: // on the headphone
			GPCR1 |= MIC_CHOICE_GPIO56;

			break;

		case MAIN_MIC: // on the phone
		default:
		    GPSR1 |= MIC_CHOICE_GPIO56;

			GPDR2 |= AMP_PWRENB;
			GAFR2_U &= ~(3<<18);
            GPCR2 |= AMP_PWRENB;

			break;
	}
}

void WaitForAudioPowerUpDown()
{
    int counter = 0;
    unsigned short RegPower;

    // Wait for power up/down complete!
	do {
	    msleep(1000);
	    TSC_RegRead(2, 5, &RegPower, 1);
	    counter++;
	} while ((RegPower & CODEC_POWERDOWN) && counter < 10);
}

void AUDIO_SetFrequence(unsigned long  dwFrequence)
{
    kprintf("AUDIO_SetFrequence dwFrequence = %d\n", dwFrequence);
    Page2Reg.RegByName.ADMUL = 1;
    Page2Reg.RegByName.ADMUR = 1;
    Page2Reg.RegByName.DAMUL = 1;
    Page2Reg.RegByName.DAMUR = 1;
    TSC_RegWrite(2, 1, &Page2Reg.RegByNumber[1], 2);

    // Wait until DAC has been muted
    WaitForAudioPowerUpDown();

    Page2Reg.RegByName.DAPD   = 1;
    Page2Reg.RegByName.ADPDL  = 1;
    Page2Reg.RegByName.ADPDR  = 1;
    TSC_RegWrite(2, 5, &Page2Reg.RegByNumber[5], 1);
    msleep(1);

    switch(dwFrequence/1000)
    {
    case 8:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_8K);
        BV_SADIV = I2S_SAM_FEQ_8;
        TSC_SetFrequence(I2SFS_8K);
        break;
    case 11:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_11K);
        BV_SADIV = I2S_SAM_FEQ_11;
        TSC_SetFrequence(I2SFS_11K);
        break;
     case 16:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_16K);
        BV_SADIV = I2S_SAM_FEQ_16;
        TSC_SetFrequence(I2SFS_16K);
        break;
    case 22:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_22K);
        BV_SADIV = I2S_SAM_FEQ_22;
        TSC_SetFrequence(I2SFS_22K);
        break;
    case 44:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_44K);
        BV_SADIV = I2S_SAM_FEQ_44;
        TSC_SetFrequence(I2SFS_44K);
        break;
     case 48:
//        SSI_SetFrequence(PCDR_PCLK_DIV3_48K);
        BV_SADIV = I2S_SAM_FEQ_48;
        TSC_SetFrequence(I2SFS_48K);
        break;
    default:
        BV_SADIV = I2S_SAM_FEQ_48;
        TSC_SetFrequence(I2SFS_48K);
        break;
    }
    msleep(1);

    Page2Reg.RegByName.ADMUL = 0;
    Page2Reg.RegByName.ADMUR = 0;
    Page2Reg.RegByName.DAMUL = 0;
    Page2Reg.RegByName.DAMUR = 0;
    TSC_RegWrite(2, 1, &Page2Reg.RegByNumber[1], 2);

}

void AUDIO_Init(void)
{
    TSC_RegRead(2, 0, Page2Reg.RegByNumber, 7);
    msleep(1);
    TSC_RegRead(2, 0, Page2Reg.RegByNumber, 7);
    msleep(1);

    Page2Reg.RegByName.MCLK = 0;     // 256 times, must
    Page2Reg.RegByName.I2SFS = I2SFS_22K;
    Page2Reg.RegByName.I2SFM = 3;    // 20-bit, I2S, MSB first, must
    TSC_RegWrite(2, 0, &Page2Reg.RegByNumber[0], 1);
    msleep(1);

    AUDIO_SetVolume(0x6f, 0x6f, 0); // Default volume
}

void AUDIO_SetVolume(unsigned char leftVol, unsigned char rightVol, unsigned long bMute)
{
    Page2Reg.RegByName.DAMUL = (unsigned short)bMute;
    Page2Reg.RegByName.DAMUR = (unsigned short)bMute;
    Page2Reg.RegByName.DAVL = leftVol & 0x7f;
    Page2Reg.RegByName.DAVR = rightVol & 0x7f;

    TSC_RegWrite(2, 2, &Page2Reg.RegByNumber[2], 1);
    msleep(1);

}

void PrePlay(int mon)
{
    Page2Reg.RegByName.DAMUL = 1;
    Page2Reg.RegByName.DAMUR = 1;

    TSC_RegWrite(2, 2, &Page2Reg.RegByNumber[2], 1);
    msleep(1);

	Page2Reg.RegByName.APD  = 0;
	Page2Reg.RegByName.AVPD = 0;
	Page2Reg.RegByName.DAPD = 0;
    Page2Reg.RegByName.SMPD = 0;
	Page2Reg.RegByName.HAPD = 0;
	//Page2Reg.RegByName.MOPD = 0;

	//if(mon)
	//{
	//	Page2Reg.RegByName.MONS = 1;
	//	Page2Reg.RegByName.MOPD = 0;
	//	Page2Reg.RegByName.HAPD = 0;
	//	TSC_RegWrite(2, 4, &Page2Reg.RegByNumber[4], 1);
	//}
    //
	//else
	//Page2Reg.RegByName.HAPD = 0;

    TSC_RegWrite(2, 5, &Page2Reg.RegByNumber[5], 1);

	WaitForAudioPowerUpDown();

	// TEST CODE FOR FINDING BUGS!
    {
        unsigned short RegPower;
        TSC_RegRead(2, 5, &RegPower, 1);
        kprintf("PrePlay: TSC2302 POWER CONTROL 0x%x\n", RegPower);
    }

	Page2Reg.RegByName.DAMUL = 0;
    Page2Reg.RegByName.DAMUR = 0;

    TSC_RegWrite(2, 2, &Page2Reg.RegByNumber[2], 1);
    msleep(1);

}


void PreRecord(int source, int mic, int mic_gain)
{
    Page2Reg.RegByName.INML  = source;     // 0: MIC, 1: LineL, 2LineR, 3: Both Line
    Page2Reg.RegByName.INMR  = source;
    if(source == MIC) {
        select_MIC_source(mic);
	    Page2Reg.RegByName.MICG = mic_gain;
	}

    TSC_RegWrite(2, 0, &Page2Reg.RegByNumber[0], 1);
    msleep(1);

    Page2Reg.RegByName.ADMUL = 0;
    Page2Reg.RegByName.ADMUR = 0;
    Page2Reg.RegByName.ADVL = 0x6f;
    Page2Reg.RegByName.ADVR = 0x6f;
    TSC_RegWrite(2, 1, &Page2Reg.RegByNumber[1], 1);
    msleep(1);

    Page2Reg.RegByName.APD   = 0;
    Page2Reg.RegByName.AVPD  = 0;
    Page2Reg.RegByName.ADPDL = 0;
//    Page2Reg.RegByName.ADPDR = 0;
    Page2Reg.RegByName.MIBPD = 0;
    Page2Reg.RegByName.SMPD  = 0;

    TSC_RegWrite(2, 5, &Page2Reg.RegByNumber[5], 1);
    msleep(1);

    // wait power on finished!!!
    WaitForAudioPowerUpDown();

	// TEST CODE FOR FINDING BUGS!
    {
        unsigned short RegPower;
        TSC_RegRead(2, 5, &RegPower, 1);
        kprintf("PreRecord: TSC2302 POWER CONTROL 0x%x\n", RegPower);
    }
}

void AftPlay()
{
    unsigned short RegPower;
    TSC_RegRead(2, 5, &RegPower, 1);
    if (RegPower & CODEC_POWERDOWN) {
        kprintf("Already power down\n");
        return; // Already power down
    }

    Page2Reg.RegByName.APD  = 1;
    Page2Reg.RegByName.AVPD = 1;
    Page2Reg.RegByName.HAPD = 1;
	Page2Reg.RegByName.DAPD = 1;
    Page2Reg.RegByName.SMPD = 1;

	TSC_RegWrite(2, 5, &Page2Reg.RegByNumber[5], 1);

    WaitForAudioPowerUpDown();

    // TEST CODE FOR FINDING BUGS!
    {
        unsigned short RegPower;
        TSC_RegRead(2, 5, &RegPower, 1);
        kprintf("AftPlay: TSC2302 POWER CONTROL 0x%x\n", RegPower);
        if ((RegPower & 0x80) == 0) {
            kprintf("\n\n\nMaybe there's something wrong!\n\n\n");
        }
    }
}

void AftRecord()
{
    unsigned short RegPower;
    TSC_RegRead(2, 5, &RegPower, 1);
    if (RegPower & CODEC_POWERDOWN) {
        kprintf("Already power down\n");
        return; // Already power down
    }

    Page2Reg.RegByName.APD   = 1;
    Page2Reg.RegByName.AVPD  = 1;
    Page2Reg.RegByName.ADPDL = 1;
    Page2Reg.RegByName.MIBPD = 1;
    Page2Reg.RegByName.SMPD  = 1;

    TSC_RegWrite(2, 5, &Page2Reg.RegByNumber[5], 1);
    msleep(1);

    WaitForAudioPowerUpDown();

    // TEST CODE FOR FINDING BUGS!
    {
        unsigned short RegPower;
        TSC_RegRead(2, 5, &RegPower, 1);
        kprintf("AftRecord: TSC2302 POWER CONTROL 0x%x\n", RegPower);
        if ((RegPower & 0x80) == 0) {
            kprintf("\n\n\nMaybe there's something wrong!\n\n\n");
        }
    }

}

void OpenSpeaker(void)
{
    kprintf("OpenSpeaker\n");
	GPSR0 |= SPKPA_SHUTDOWN;
	(void *) GPSR0;
}

void CloseSpeaker(void)
{
    kprintf("CloseSpeaker\n");
	GPCR0 |= SPKPA_SHUTDOWN;
	(void *) GPCR0;
}
